package com.vending.management.service.impl;


import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.util.StrUtil;
import com.vending.common.constant.TaskStatusConstants;
import com.vending.common.constant.TaskTypeConstants;
import com.vending.common.constant.VmStatusConstants;
import com.vending.common.exception.ServiceException;
import com.vending.common.utils.DateUtils;
import com.vending.management.domain.Emp;
import com.vending.management.domain.TaskDetails;
import com.vending.management.domain.VendingMachine;
import com.vending.management.domain.dto.TaskDetailsDto;
import com.vending.management.domain.dto.TaskDto;
import com.vending.management.domain.vo.TaskVo;
import com.vending.management.mapper.EmpMapper;
import com.vending.management.mapper.VendingMachineMapper;
import com.vending.management.service.ITaskDetailsService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.vending.management.mapper.TaskMapper;
import com.vending.management.domain.Task;
import com.vending.management.service.ITaskService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 * 工单Service业务层处理
 *
 * @author ruoyi
 * @date 2025-11-01
 */
@Service
public class TaskServiceImpl implements ITaskService
{
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private VendingMachineMapper vendingMachineMapper;
    @Autowired
    private EmpMapper empMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ITaskDetailsService taskDetailsService;



    /**
     * 查询工单
     *
     * @param taskId 工单主键
     * @return 工单
     */
    @Override
    public Task selectTaskByTaskId(Long taskId)
    {
        return taskMapper.selectTaskByTaskId(taskId);
    }

    /**
     * 查询工单列表
     *
     * @param task 工单
     * @return 工单
     */
    @Override
    public List<Task> selectTaskList(Task task)
    {
        return taskMapper.selectTaskList(task);
    }

    /**
     * 新增工单
     *
     * @param task 工单
     * @return 结果
     */
    @Override
    public int insertTask(Task task)
    {
        task.setCreateTime(DateUtils.getNowDate());
        return taskMapper.insertTask(task);
    }

    /**
     * 修改工单
     *
     * @param task 工单
     * @return 结果
     */
    @Override
    public int updateTask(Task task)
    {
        task.setUpdateTime(DateUtils.getNowDate());
        return taskMapper.updateTask(task);
    }

    /**
     * 批量删除工单
     *
     * @param taskIds 需要删除的工单主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskIds(Long[] taskIds)
    {
        return taskMapper.deleteTaskByTaskIds(taskIds);
    }

    /**
     * 删除工单信息
     *
     * @param taskId 工单主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskId(Long taskId)
    {
        return taskMapper.deleteTaskByTaskId(taskId);
    }

    /**
     * 查询工单列表
     *
     * @param task 工单
     * @return TaskVo集合
     */
    @Override
    public List<TaskVo> selectTaskVoList(Task task) {
        return taskMapper.selectTaskVoList(task);
    }

    /**
     * 新增运营，运维工单
     *
     * @param taskDto 工单
     * @return 结果
     */
    @Transactional
    @Override
    public int insertTaskDto(TaskDto taskDto) {
        //1.查询售货机是否存在
        VendingMachine vendingMachine = new VendingMachine();
        vendingMachine.setInnerCode(taskDto.getInnerCode());
        List<VendingMachine> vendingMachines = vendingMachineMapper.selectVendingMachineList(vendingMachine);
        if (vendingMachines == null || vendingMachines.isEmpty()) {
            throw new ServiceException("售货机不存在");
        }
        VendingMachine vm = vendingMachines.get(0);
        //2.校验售货机状态与工单类型是否匹配
        checkCreateTask(vm.getVmStatus(), taskDto.getProductTypeId());
        //3.检查是否存在未完成的相同类型的工单
        hasTask(taskDto);
        //4.查询员工是否存在
        Emp emp = new Emp();
        emp.setId(taskDto.getUserId());
        Emp e = empMapper.selectEmpById(emp.getId());
        if (e == null) {
            throw new ServiceException("员工不存在");
        }
        //5.校验员工区域是否匹配
        if (!vm.getRegionId().equals(e.getRegionId())) {
            throw new ServiceException("员工区域与售货机区域不一致");
        }
        //6.保存工单
        Task task = new Task();
        BeanUtils.copyProperties(taskDto, task);
        task.setTaskStatus(TaskStatusConstants.TASK_STATUS_CREATE);//设置工单状态为创建(待处理)
        task.setUserName(e.getUserName());//执行人名称
        task.setRegionId(vm.getRegionId());//所属区域Id
        task.setAddr(vm.getAddr());//设备地址
        task.setCreateTime(DateUtils.getNowDate());//工单创建时间
        task.setTaskCode(createTaskCode());//设置工单编号
        int result = taskMapper.insertTask(task);//保存工单
        //7.判断是否为补货工单，如果是则保存工单详情
        if (TaskTypeConstants.TASK_TYPE_SUPPLY.equals(taskDto.getProductTypeId())) {
            //创建补货工单详情对象
            List<TaskDetailsDto> details = taskDto.getDetails();
            if (CollectionUtils.isEmpty(details)) {
                throw new ServiceException("补货工单详情不能为空");
            }
            List<TaskDetails> taskDetailsList =details.stream().map(detail -> {
                TaskDetails taskDetails = new TaskDetails();
                BeanUtils.copyProperties(detail, taskDetails);
                return taskDetails;
            }).collect(Collectors.toList());
            //批量新增
            taskDetailsService.batchInsertTaskDetails(taskDetailsList);

        }
        return result;
    }

    @Override
    public int cancelTask(Task task) {
        //1.判断工单状态是否可以取消
        //先根据工单Id查询工单
        Task taskDb = taskMapper.selectTaskByTaskId(task.getTaskId());
        //判断工单状态是否为已取消，如果是则抛出异常
        if (TaskStatusConstants.TASK_STATUS_CANCEL.equals(taskDb.getTaskStatus())) {
            throw new ServiceException("工单已取消，不能重复取消");
        }
        //判断工单状态是否为已完成，如果是则抛出异常
        if (TaskStatusConstants.TASK_STATUS_FINISH.equals(taskDb.getTaskStatus())) {
            throw new ServiceException("工单已完成，不能取消");
        }
        //2.设置更新字段
        task.setTaskStatus(TaskStatusConstants.TASK_STATUS_CANCEL); //工单状态为取消
        task.setUpdateTime(DateUtils.getNowDate());//更新时间
        //3.更新工单
        return taskMapper.updateTask(task);
    }

    //生成并获取当天的工单编号(Redis),"yyyyMMdd"+四位数字自增 唯一标识
    private String createTaskCode(){
        //获取当前日期(yyyyMMdd)
        String currentDate = DateUtils.getDate().replaceAll("-", "");
        String key = "taskCode." + currentDate;
        //判断Redis中是否存在key
        if (!redisTemplate.hasKey(key)) {
            //如果不存在，初始化值为1，设置过期时间为1天
            redisTemplate.opsForValue().set(key, 1, Duration.ofDays(1));
            //返回工单编号(日期+0001)
            return currentDate + "0001";
        }
        //如果存在，计数器+1(0002),确保字符串长度为4
        return currentDate+StrUtil.padPre(redisTemplate.opsForValue().increment(key).toString(), 4, "0");
    }

    //检查是否存在未完成的相同类型的工单
    private void hasTask(TaskDto taskDto) {
        //创建task条件对象，并设置设备编号和工单类型,以及工单类型为进行中
        Task taskParams = new Task();
        taskParams.setInnerCode(taskDto.getInnerCode());
        taskParams.setProductTypeId(taskDto.getProductTypeId());
        taskParams.setTaskStatus(TaskStatusConstants.TASK_STATUS_PROGRESS);
        //查询是否存在未完成的相同类型的工单
        List<Task> tasks = taskMapper.selectTaskList(taskParams);
        //如果存在未完成的相同类型的工单，抛出异常
        if (tasks != null && !tasks.isEmpty()) {
            throw new ServiceException("该设备已存在未完成的相同类型工单，不能重复创建");
        }
    }

    //校验售货机状态与工单类型是否匹配
    private void checkCreateTask(Long vmStatus, Long productTypeId){
        //如果是投放工单，设备在运行中，抛出异常
        if (vmStatus == VmStatusConstants.VM_STATUS_ON && productTypeId == TaskTypeConstants.TASK_TYPE_DEPLOY) {
            throw new ServiceException("设备在运行中，请勿重复投放");
        }
        //补货工单，设备不在运行中，抛出异常
        if (vmStatus == VmStatusConstants.VM_STATUS_OFF && productTypeId == TaskTypeConstants.TASK_TYPE_SUPPLY) {
            throw new ServiceException("设备不在运行中，无法进行补货操作");
        }
        //维修工单，设备不在运行中，抛出异常
        if (vmStatus == VmStatusConstants.VM_STATUS_OFF && productTypeId == TaskTypeConstants.TASK_TYPE_REPAIR) {
            throw new ServiceException("设备不在运行中，请勿进行维修操作");
        }
        //撤机工单，设备不在运行中，抛出异常
        if (vmStatus == VmStatusConstants.VM_STATUS_OFF && productTypeId == TaskTypeConstants.TASK_TYPE_REVOKE) {
            throw new ServiceException("设备不在运行中，请勿进行撤机操作");
        }
    }
}
